package leetcode.pre1000;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * 给定一个整数数组 A，返回其中元素之和可被 K 整除的
 * <p>
 * （连续、非空）子数组的数目。
 * <p>
 * <p>
 * 示例：
 * <p>
 * 输入：A = [4,5,0,-2,-3,1], K = 5
 * 输出：7
 * 解释：
 * 有 7 个子数组满足其元素之和可被 K = 5 整除：
 * [4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]
 * <p>
 * <p>
 * 其他见{@link leetcode.a_总结分布.Code07_数组子数组问题}
 *
 * TODO 剩余定理  时间O(n)
 *
 * @date 2020/5/24 18:09
 */
public class Code974_和可被K整除的子数组 {
    public static void main(String[] args) {
        int[] A = {4, 5, 0, -2, -3, 1};
        int k = 5;
        System.out.println(process1(A, k));
    }

    /**
     * 方式1：暴力遍历所有,OJ超时
     */
    public static int process1(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        List<int[]> res = new LinkedList<>();
        for (int i = 0; i < nums.length; i++) {
            int sum = 0;
            for (int j = i; j < nums.length; j++) {
                sum += nums[j];
                if ((sum % k) == 0) {
                    res.add(Arrays.copyOfRange(nums, i, j + 1));
                }
            }
        }
        res.forEach(ints -> System.out.println(Arrays.toString(ints)));
        return res.size();
    }

    /**
     * 方式2：动态规划
     * dp[i][j]表示从i到j的连续子序列的和
     * 其中 j >= i
     * dp[i][j] = dp[i][j-1] + nums[j]
     * dp[i][i] = nums[i],
     *
     * OJ超出内存
     */
    public static int process2(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int[][] dp = new int[nums.length][nums.length];
        int count = 0;
        for (int i = 0; i < nums.length; i++) {
            dp[i][i] = nums[i];
            if (dp[i][i] % k == 0) count++;
            //j >= i,j<i没有意义
            for (int j = i + 1; j < nums.length; j++) {
                dp[i][j] = dp[i][j - 1] + nums[j];
                if (dp[i][j] % k == 0) count++;
            }
        }
        return count;
    }
}
